home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / multitsk.arc / TASKFUNC.ASM < prev    next >
Assembly Source File  |  1986-03-05  |  12KB  |  325 lines

  1.  
  2.           PAGE  60,132
  3.  
  4. ;                  Multi-tasking subroutines for Lattice C
  5. ;                          (large model only)
  6. ;
  7. ;
  8. ;       These functions are based on the technique presented by
  9. ;       Richard Foard in PC Tech Journal, March 1986 in the article
  10. ;       "Multitasking Methods".  The basic mechanism is the same; I
  11. ;       have changed the names of the functions to suit my own
  12. ;       background.  The only real differences are as follows:
  13. ;
  14. ;         1.  The interfacing is specific to Lattice V2.15, using the
  15. ;             large memory model.  Although the DOS.MAC header is
  16. ;             referenced, much of the code is dependent on 4-byte
  17. ;             pointers and FAR calls.
  18. ;
  19. ;         2.  In addition to the stack frame, each of the subtasks is
  20. ;             allowed (required?) to have a static, global data area
  21. ;             independent of all others.  The truly global data item
  22. ;             COMANCH should be defined as a pointer to an appropriate
  23. ;             structure.  The task switch routines will assure that
  24. ;             COMANCH always points to the proper area.  The inittask
  25. ;             and attach functions accept a pointer to the area in
  26. ;             their parameter lists.
  27. ;
  28. ;         3.  Instead of wait and post, I have implemented enq and
  29. ;             deq functions to allow serialization of resources.
  30. ;             For me, at least, these are a more natural mechanism.
  31. ;
  32. ;         4.  The yield function will skip over any task which does not have
  33. ;             a non-zero data pointer, assuming that the task has terminated.
  34. ;
  35. ;         5.  The function taskcnt returns the number of active tasks - this
  36. ;             can be checked by the "main" task to decide whether termination
  37. ;             is reasonable.  When a value of 1 is returned, only the calling
  38. ;             task is active.
  39. ;
  40. ;     Notes:
  41. ;
  42. ;         If an attempt is made to attach more than MAXTASKS, return is made
  43. ;         to DOS via _exit with a return code of 1.
  44. ;
  45. ;         If the last remaining task invokes the stop function, yield will
  46. ;         loop forever.
  47. ;
  48. ;         A subtask should *never* attempt to return to its caller;
  49. ;         the stack used for the subtask does not carry the caller's
  50. ;         environment, and the system would hang for sure.   The proper
  51. ;         way to terminate a subtask is via stop().
  52. ;
  53. ;         It is unwise for any task to return to DOS unless it is known
  54. ;         that no other tasks remain;  use taskcnt() to find out.
  55. ;
  56. ;
  57. ;      March 1986                       Ed Legowski
  58. ;                                       24 Cannonade Dr
  59. ;                                       Marlboro, NJ 07746
  60. ;
  61. ;
  62. ;         void inittask(comptr)
  63. ;                  char *comptr    - pointer to tcb's common area
  64. ;
  65. ;                  prepares environment for use - on exit caller is the
  66. ;                  first active task.  Note: the public pointer COMANCH
  67. ;                  must have already been initialized to point to the
  68. ;                  proper data area.
  69. ;
  70. ;         int attach(comptr, stackptr, stacksize)
  71. ;                  char *comptr    - pointer to tcb's common area
  72. ;                  char *stackptr  - pointer to stack space
  73. ;                  int stacksize   - size of stack
  74. ;
  75. ;                  creates and activates a subtask.  returns FALSE to
  76. ;                  the calling task, and true to the new task.
  77. ;
  78. ;              Typical sequence is:
  79. ;                 if (attach(&area,&stack,sizeof stack)) subtask();
  80. ;
  81. ;         void yield()
  82. ;                  allows a task switch to occur - the next task (in
  83. ;                  round-robin order) is 'dispatched'.
  84. ;
  85. ;         int enq(lockword)
  86. ;                  int *lockword;
  87. ;
  88. ;                  waits unit the specified lockword becomes free, then
  89. ;                  takes ownership.
  90. ;                  Returns 0 if ok, !0 if already owned.
  91. ;
  92. ;         void deq(lockword)
  93. ;                  int *lockword;
  94. ;
  95. ;                  releases the specified lock
  96. ;
  97. ;         void stop()
  98. ;                  destroys the calling task
  99. ;
  100. ;         int taskcnt()
  101. ;                  returns the number of active tasks
  102. ;
  103. ;
  104. ;
  105. ;
  106.  
  107.           EXTRN    COMANCH:FAR
  108.           EXTRN    _EXIT:FAR
  109.  
  110.                 if1
  111.                 include L:\l\DOS.MAC
  112.                 endif
  113.  
  114. TCB       STRUC
  115. tcbstack  dd       ?               ;saved stack frame
  116. tcbcommon dd       ?               ;tasks common block
  117. TCB       ENDS
  118.  
  119. ATTACHPL  STRUC
  120. attbp     dw       ?              ;callers bp
  121. attret    dd       ?              ;return address
  122. attcomptr dd       ?              ;pointer to common
  123. attstack  dd       ?              ;pointer to stack
  124. attsize   dw       ?              ;size of stack
  125. ATTACHPL  ENDS
  126.  
  127. EVENTPL   STRUC
  128. evnbp     dw       ?              ;caller's bp
  129. evnret    dd       ?              ;return address
  130. evnlock   dd       ?              ;pointer to lockword
  131. EVENTPl   ENDS
  132.  
  133.           DSEG
  134. MAXTASKS  equ      4              ;maximum number of tasks
  135.  
  136. tasktable equ      this byte
  137.           REPT     MAXTASKS
  138.           TCB      <0,0>
  139.           ENDM
  140. endtable  equ      this byte
  141.  
  142. curtask   dw       0               ;ptr to current tcb
  143. actvtasks dw       0               ;current task count
  144. commonptr dd       COMANCH
  145.           ENDDS
  146.  
  147.           PSEG
  148.  
  149.           BEGIN    inittask
  150.  
  151.           push     bp             ;save callers reg
  152.           mov      bp,sp          ;set addressing to parm list
  153.  
  154. ;    first clear the task table
  155.  
  156.           sub      ax,ax
  157.           mov      bx,offset tasktable
  158.           mov      cx,MAXTASKS
  159. initl:    mov      [bx],ax         ;clear the stack reference
  160.           mov      [bx+2],ax
  161.           mov      [bx+4],ax       ;clear the common ptr
  162.           mov      [bx+6],ax
  163.           add      bx,SIZE TCB     ;point next tcb
  164.           loop     initl           ;do them all
  165.  
  166. ;    now establish us as the current task
  167.  
  168.           mov      curtask,offset tasktable
  169.           mov      actvtasks,1
  170.           mov      bx,offset tasktable
  171.           mov      ax,word ptr [bp].attcomptr  ;set the common pointer
  172.           mov      word ptr [bx].tcbcommon,ax
  173.           mov      ax,word ptr [bp].attcomptr+2
  174.           mov      word ptr [bx].tcbcommon+2,ax
  175.  
  176.           pop      bp             ;restore caller's reg
  177.           ret
  178. inittask  ENDP
  179.  
  180.           BEGIN    yield
  181.  
  182. ;   first save status of current task
  183.  
  184.           push     bp             ;preserve frame
  185.           mov      bx,curtask     ;point to current tcb
  186.           mov      word ptr [bx].tcbstack,sp  ;preserve stack
  187.           mov      word ptr [bx].tcbstack+2,ss
  188.  
  189. ;   locate next task to dispatch
  190.  
  191. yield0:   add      bx,SIZE TCB    ;point next TCB
  192.           cmp      bx,offset endtable  ;q/end of round robin table
  193.           jb       yield1              ;bin - test the entry
  194.           mov      bx,offset tasktable ;point back to the beginning
  195. yield1:   cmp      word ptr [bx].tcbcommon+2,0   ;q/is task active
  196.           je       yield0              ;bin - keep trying
  197.  
  198. ;  restore status of this task
  199.           mov      curtask,bx     ;make new task current
  200.           les      ax,[bx].tcbcommon ; point to task common
  201.           mov      si,es          ;save segment for common
  202.           les      di,commonptr   ;point to the C pointer
  203.           mov      es:[di],ax
  204.           mov      es:[di+2],si
  205.  
  206. ;  restore the stack - this is done disabled to prevent possible
  207. ;     problems with sp and ss regs being out of synch if an interrupt
  208. ;     should occur
  209.  
  210.           cli
  211.           mov      ss,word ptr [bx].tcbstack+2
  212.           mov      sp,word ptr [bx].tcbstack
  213.           sti
  214.           pop      bp
  215.           mov      ax,1
  216.           ret
  217. yield     ENDP
  218.  
  219.           BEGIN    attach
  220.  
  221.           mov      ax,actvtasks   ;verify task
  222.           cmp      ax,MAXTASKS    ;     count
  223.           jne      attach0        ;        not exceeded
  224.           mov      ax,1           ; all tcb's in use
  225.           push     ax             ;   terminate with error
  226.           call     _exit
  227.  
  228. attach0:
  229.           inc      ax             ;number of tasks
  230.           mov      actvtasks,ax   ;preserve it
  231.  
  232. ;   locate first available tcb
  233.  
  234.  
  235.           mov      bx,offset tasktable
  236.           mov      cx,MAXTASKS
  237. attach1:  cmp      word ptr [bx].tcbcommon+2,0   ;q/is it in use?
  238.           je       attach2        ;bin - use this one
  239.           add      bx,SIZE TCB    ;point next one
  240.           loop     attach1        ;keep looking
  241.           mov      ax,2           ;empty tcb not found
  242.           push     ax             ;   terminate with error 2
  243.           call     _exit
  244.  
  245. ;   initialize the new tcb
  246.  
  247. attach2:  push     bp             ;save callers bp
  248.           mov      bp,sp          ;point to parm frame
  249.           mov      ax,word ptr [bp].attcomptr  ;set the common pointer
  250.           mov      word ptr [bx].tcbcommon,ax
  251.           mov      ax,word ptr [bp].attcomptr+2
  252.           mov      word ptr [bx].tcbcommon+2,ax
  253.           mov      ax,word ptr [bp].attstack+2  ;stack segment
  254.           mov      word ptr [bx].tcbstack+2,ax
  255.           mov      ax,word ptr [bp].attstack  ;  stack offset
  256.           add      ax,word ptr [bp].attsize   ;      adjust by size
  257.           mov      dx,ax                      ;save stack origin
  258.           sub      ax,SIZE ATTACHPL  ;  allow pop of parms
  259.           mov      word ptr [bx].tcbstack,ax
  260.  
  261. ;   initialize the stack for the new task
  262.  
  263.           les      di,[bx].tcbstack  ;point to the stack
  264.           mov      cx,SIZE ATTACHPL
  265.           cld
  266. attach3:  mov      al,[bp]
  267.           stosb
  268.           inc      bp
  269.           loop     attach3
  270.           les      di,[bx].tcbstack  ;point to the stack
  271.           mov      es:[di],dx        ;set bp for new task = top of stack
  272.  
  273. ;    return to calling task
  274.  
  275.           pop      bp
  276.           sub      ax,ax
  277.           ret
  278.  
  279. attach    ENDP
  280.  
  281.           BEGIN    enq
  282.           push     bp             ;save bp
  283.           mov      bp,sp          ;origin of parm list
  284.  
  285. enq0:     les      di,[bp].evnlock ;point event counter
  286.           mov      ax,es:[di]     ;get the counter
  287.           or       ax,ax          ;q/do we need to wait
  288.           jz       enq1           ;bin - return to caller
  289.           cmp      ax,curtask     ;q/caller already own it
  290.           je       enq1           ;biy
  291.           call     yield          ;allow transfer
  292.           jmp      enq0           ;try again
  293.  
  294. enq1:     mov      bx,curtask     ;show which task owns it
  295.           mov      es:[di],bx     ;take control of the lock
  296.           pop      bp             ;return caller's bp
  297.           ret
  298. enq       ENDP
  299.  
  300.           BEGIN    deq
  301.           push     bp             ;save user's bp
  302.           mov      bp,sp
  303.           les      di,[bp].evnlock     ;point user's event counter
  304.           mov      word ptr es:[di],0  ;clear the lock
  305.           pop      bp
  306.           ret
  307. deq       ENDP
  308.  
  309.           BEGIN    stop
  310.  
  311.           mov      bx,curtask     ;point to the current task
  312.           mov      word ptr [bx].tcbcommon+2,0   ;show task inactive
  313.           dec      actvtasks      ;reduce count of tasks
  314.           call     yield          ;we will not return from here
  315.  
  316. stop      ENDP
  317.  
  318.           BEGIN    taskcnt
  319.           mov      ax,actvtasks   ;return number of active tasks
  320.           ret
  321. taskcnt   ENDP
  322.  
  323.           ENDPS
  324.           END
  325.